from abc import ABCMeta, abstractmethod
from typing import Any, Callable, NoReturn, Optional, Tuple

try:
    from .event import Event
except:
    from event import Event  # type: ignore

__all__ = ['Entity']


class Entity(metaclass=ABCMeta):
    @abstractmethod
    def char_rep(self) -> Optional[str]:
        """Returns the character that can represent the entity.

        Returns:
            - `Optional[str]`: The representative character, or `None` if
            there is no representative character.
        """

    @abstractmethod
    def backgrnd_rep(self) -> Optional[Tuple[str, str]]:
        """Returns the ANSI code that sets the background color that
        should be used when displaying this entity and the reset code.

        Returns:
            - `Optional[Tuple[str, str]]`: The background ANSI code and its
            reset code, or `None` if there is no need for background color.
        """

    @abstractmethod
    def place_river(self) -> bool:
        """Returns whether a river can be placed at this spot.

        Returns:
            - `bool`: Whether a river can be placed here.
        """

    @abstractmethod
    def place_mountain(self) -> bool:
        """Returns whether a mountain can be placed at this spot.

        Returns:
            - `bool`: Whether a mountain can be placed here.
        """

    @abstractmethod
    def place_tree(self) -> bool:
        """Returns whether a tree can be placed at this spot.

        Returns:
            - `bool`: Whether a tree can be placed here.
        """

    @abstractmethod
    def place_mineral(self) -> bool:
        """Returns whether minerals can be placed at this spot.

        Returns:
            - `bool`: Whether minerals can be placed here.
        """

    @abstractmethod
    def place_building(self, building) -> bool:
        """Returns whether a building can be built at this spot.

        Args:
            - `building` (`Building`): The building to place.

        Returns:
            - `bool`: Whether the building can be built at this spot.
        """

    @abstractmethod
    def crossable(self, unit) -> bool:
        """Returns whether a unit can cross this entity.

        Args:
            - `unit` (`Unit`): The unit that is trying to cross the entity.

        Returns:
            - `bool`: Whether a unit can cross this entity.
        """

    @abstractmethod
    def onevent(self, ev: Event) -> Optional[Callable[[Any, Tuple[int, int], Event], NoReturn]]:
        """Event callback.

        Returns:
            - `Optional[Callable[[Board, Tuple[int, int], Event], int]]`:
            The callback function to be called when an event happens. Takes
            the current board, the position of the entity in (column, row)
            form, and the event as arguments. Does not return anything.
        """
        def callback(board: Any, position: Tuple[int, int], ev: Event) -> NoReturn:
            """Callback function to be called when an event happens.

            Args:
                - `board` (`Board`): The current board.
                - `position` (`Tuple[int, int]`): The position of the unit
                in (column, row) form.
            """

    __repr__ = char_rep
